import {
  DatafeedConfiguration,
  ErrorCallback,
  HistoryCallback,
  IDatafeedChartApi,
  IExternalDatafeed,
  LibrarySymbolInfo,
  OnReadyCallback,
  ResolutionString,
  ResolveCallback,
  SubscribeBarsCallback,
  SearchSymbolsCallback,
} from '../../../charting_library/datafeed-api';

interface Window {
  ws: WebSocket;
  onRealtimeCallback?: SubscribeBarsCallback;
}
declare var window: Window;

export interface UdfCompatibleConfiguration extends DatafeedConfiguration {
  // tslint:disable
  supports_search?: boolean;
  supports_group_request?: boolean;
  // tslint:enable
}
/**
 * This class implements interaction with UDF-compatible datafeed.
 * See UDF protocol reference at https://github.com/tradingview/charting_library/wiki/UDF
 */
export class UDFCompatibleDatafeed implements IExternalDatafeed, IDatafeedChartApi {
  
  public onReady(callback: OnReadyCallback): void {
    setTimeout(() => {
      callback(<UdfCompatibleConfiguration>{
        supports_search: true,
        supported_resolutions: ['1', '5', '15', '30', '60', '120', '240', '360', '720', '1D', '1W', '1M'],
      });
    });
  }

  public async resolveSymbol(symbolName: string, onResolve: ResolveCallback, onError: ErrorCallback) {
    setTimeout(() => {
      onResolve({
        name: symbolName,
        ticker: symbolName,
        full_name: symbolName,
        description: '',
        session: '24x7',
        type: 'bitcoin',
        exchange: '',
        listed_exchange: '',
        timezone: 'Asia/Shanghai',
        pricescale: 10 ** 8,
        minmov: 1,
        has_intraday: true,
        intraday_multipliers: ['1', '5', '15', '30', '60', '120', '240', '360', '720'],
        supported_resolutions: ['1', '5', '15', '30', '60', '120', '240', '360', '720', '1D'],
        has_daily: true,
        has_weekly_and_monthly: false,
        has_empty_bars: false,
      });
      
    });
  }

  public searchSymbols(userInput: string, exchange: string, symbolType: string, onResult: SearchSymbolsCallback) {}

  public getKline(symbol: string, resolution: string, from: number, to: number): Promise<any> {
    return new Promise((resolve, reject) => {
      window.ws.onmessage = (evt) => {
        if (evt.data) {
          const data = JSON.parse(evt.data);
          if (data.id === 10) {
            resolve(data);
          }
        }
			};
      window.ws.onerror = (err) => {
        reject(err);
      };
      const params = {"method":"kline.query","params":[symbol,from,to,(+resolution)*60],"id":10};
      window.ws.send(JSON.stringify(params));
    });
  }

  public async getBars(
    symbolInfo: LibrarySymbolInfo,
    resolution: ResolutionString,
    rangeStartDate: number,
    rangeEndDate: number,
    onResult: HistoryCallback,
    onError: ErrorCallback,
  ) {
    let res = await this.getKline(symbolInfo.name, resolution, rangeStartDate, rangeEndDate);
    const bars: any[] = [];
    if (res.result.length > 0) {
      res.result.reduce((prev: any, cur: any) => {
        bars.push({
          time: cur[0] * 1000,
          open: +cur[1],
          close: +cur[2],
          high: +cur[3],
          low: +cur[4],
          volume: +cur[5],
        });
        return prev;
      }, {});
    }
    onResult(bars, { noData: bars.length === 0 });
  }

  public subscribeBars(
    symbolInfo: LibrarySymbolInfo,
    resolution: ResolutionString,
    onTick: SubscribeBarsCallback,
    listenerGuid: string,
    onResetCacheNeededCallback: () => void,
  ): void {
    window.onRealtimeCallback = onTick;
    window.ws.onmessage = (evt) => {
      if (evt.data) {
        const res = JSON.parse(evt.data);
        if (res.method === 'kline.update' && res.params && res.params.length > 0) {
          const cur = res.params[res.params.length - 1];
          onTick({
            time: cur[0] * 1000,
            open: +cur[1],
            close: +cur[2],
            high: +cur[3],
            low: +cur[4],
            volume: +cur[5],
          });
        }
      }
    };
    const params = {"method":"kline.subscribe","params":[symbolInfo.name,(+resolution)*60],"id":20};
    window.ws.send(JSON.stringify(params));
  }

  public unsubscribeBars(listenerGuid: string): void {
    const [symbol, resolution] = listenerGuid.split('_');
    const params = {"method":"kline.unsubscribe","params":[symbol, (+resolution)*60],"id":30};
    window.ws.send(JSON.stringify(params));
  }
}
